package com.hucsmn.examsystem.model;

import com.hucsmn.examsystem.common.User;
import com.hucsmn.examsystem.server.ExamServerException;

import java.io.*;
import java.util.HashMap;
import java.util.Map;

/**
 * 用户数据库。
 */
public class UserDatabase implements Serializable {
    private static final long serialVersionUID = 480723084304031803L;
    private final Map<Integer, User> users = new HashMap<>();
    private final Map<String, User> index = new HashMap<>();
    private User admin = new User(0, "admin", "123456");
    private int nextId = 1;

    {
        index.put(admin.getName(), admin);
    }

    public UserDatabase() {
    }

    public UserDatabase(User admin) {
        if (admin == null) {
            throw new NullPointerException();
        }
        this.admin = admin;
    }

    /**
     * 导入数据库。
     *
     * @param file 数据库路径。
     * @return 导入的数据库。
     * @throws IOException 数据库读取错误、数据库格式不正确、或数据库状态不一致。
     */
    public static UserDatabase load(File file) throws IOException {
        try (ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file)))) {
            Object obj = in.readObject();
            if (!(obj instanceof UserDatabase)) {
                throw new ClassCastException();
            }
            UserDatabase db = (UserDatabase) obj;
            if (!db.validate()) {
                throw new ExamServerException("invalid user database");
            }
            return db;
        } catch (ClassNotFoundException | ClassCastException e) {
            throw new ExamServerException("not a user database");
        }
    }

    /**
     * 通过编号获取用户信息。
     *
     * @param id 用户编号。
     * @return 用户信息的拷贝，不存在时返回 null。
     */
    public synchronized User get(int id) {
        User user;
        if (id == 0) {
            user = admin;
        } else {
            user = users.get(id);
        }

        if (user != null) {
            try {
                user = (User) user.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
                return null;
            }
        }
        return user;
    }

    /**
     * 通过用户名获取用户信息。
     *
     * @param name 用户名。
     * @return 用户信息的拷贝，不存在时返回 null。
     */
    public synchronized User get(String name) {
        User user = index.get(name);
        if (user != null) {
            try {
                user = (User) user.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
                return null;
            }
        }
        return user;
    }

    /**
     * 将用户信息录入，返回用户编号。
     *
     * @param user 待录入的用户信息，用户编号忽略。
     * @return 用户编号，用户名重复时返回 -1。
     */
    public synchronized int add(User user) {
        if (user == null) {
            throw new NullPointerException();
        }

        if (index.containsKey(user.getName())) {
            return -1;
        }

        try {
            user = (User) user.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return -1;
        }

        user.setId(nextId);
        users.put(nextId, user);
        index.put(user.getName(), user);
        return nextId++;
    }

    /**
     * 通过编号删除指定用户信息。
     *
     * @param id 用户编号。
     * @return 用户信息存在且成功删除返回真。
     */
    public synchronized boolean delete(int id) {
        User user = users.remove(id);
        if (user == null) {
            return false;
        }
        index.remove(user.getName());
        return true;
    }

    /**
     * 通过用户名删除指定用户信息。
     *
     * @param name 用户名。
     * @return 用户信息存在且成功删除返回真。
     */
    public synchronized boolean delete(String name) {
        User user = index.remove(name);
        if (user == null) {
            return false;
        }
        users.remove(user.getId());
        return true;
    }

    /**
     * 更新用户信息。
     *
     * @param id   待更新的用户信息编号。
     * @param user 用户信息内容，忽略编号。
     * @return 原用户编号存在且新的用户名不与其他用户信息冲突时，修改成功返回真。
     */
    public synchronized boolean update(int id, User user) {
        if (user == null) {
            throw new NullPointerException();
        }

        User u = index.get(user.getName());
        if (u != null && u.getId() != id) {
            return false;
        }

        try {
            user = (User) user.clone();
            user.setId(id);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return false;
        }

        if (id == 0) {
            index.remove(admin.getName());
            index.put(user.getName(), user);
            admin = user;
            return true;
        } else {
            User old = users.replace(id, user);
            if (old == null) {
                return false;
            }
            index.remove(old.getName());
            index.put(user.getName(), user);
            return true;
        }
    }

    /**
     * 列举全部用户。
     *
     * @return 用户信息列表。
     */
    public synchronized User[] select() {
        return index.values().toArray(new User[0]);
    }

    /**
     * 导出整个数据库。
     *
     * @param file 数据库路径。
     * @throws IOException 数据库写入异常。
     */
    public synchronized void save(File file) throws IOException {
        try (ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)))) {
            out.writeObject(this);
            out.flush();
        }
    }

    /**
     * 检测刚刚导入的数据库，内部状态是否一致。
     *
     * @return 状态一致返回真。
     */
    private boolean validate() {
        //TODO: validate internal state.
        return true;
    }
}
